import { isArray, isMap, isObj, isObject, isSet } from "./Utils";

/**
 * 获取变量类型
 * @param value
 * @return 变量类型(string，全部小写字母)
 * @since V1.0.0
 */
export function getTag(value: any): string {
    return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}


/**
 * 移除对象中属性值为空、null、undefined的键值对
 * <p>！！！如果参数不是Object类型，则参数值不做任何处理，原样返回</p>
 * @param arg Object对象
 * @returns 处理后的对象
 * @since V1.3.0
 */
export function deleteEmptyProperty(arg: any): any {
    if (!isObj(arg)) {
        console.warn(`deleteEmptyProperty() ==> 参数值类型不是Object类型，不作任何处理，直接返回.`);
        return arg;
    }
    Object.keys(arg).forEach(key => {
        if (arg[key] === '' || arg[key] == null) {
            Reflect.deleteProperty(arg, key);
        }
    });
    return arg;
}

/** Used to check objects for own properties. */
const hasOwnProperty = Object.prototype.hasOwnProperty;

/**
 * 初始化克隆对象
 * @param object
 */
export function initCloneObj(object: any) {
    const Ctor = object.constructor;
    switch (getTag(object)) {
        case 'number':
        case 'string':
        case 'boolean':
        case 'date':
            return new Ctor(object);
        case 'map':
        case 'set':
            return new Ctor;
        case 'regexp': {
            const regexpObj = new Ctor(object.source, /\w*$/.exec(object));
            regexpObj.lastIndex = object.lastIndex;
            return regexpObj;
        }
        case 'object':
            return {};
        case 'array':
            return [];
        default:
            return object;
    }
}

/**
 * 深拷贝
 * @param value
 * @since V1.0.0
 * <p>深拷贝对象自身的属性。</p>
 * <ul>
 *     <li>1. 支持深拷贝的数据类型有number、string、boolean、null、undefined、Number、String、Boolean、Map、Set、Object、Array、RegExp、Date。</li>
 *     <li>2. Int8Array、Uint8Array、Int16Array等对象数据只会进行简单的复制，不会进行深拷贝。</li>
 * </ul>
 */
export function cloneDeep(value: any): any {
    if (!isObject(value)) { // 如果value值为基本数据类型，则直接返回
        return value;
    }
    let result = initCloneObj(value); // 根据value的数据类型初始化克隆对象
    if (isMap(value)) { // 如果value值为Map类型
        value.forEach((subValue: any, key: any) => {
            result.set(key, cloneDeep(subValue));
        });
        return result;
    } else if (isSet(value)) { // 如果value值为Set类型
        value.forEach((subValue: any) => {
            result.add(cloneDeep(subValue));
        });
        return result;
    } else if (isObj(value) || isArray(value)) { // 如果value值类型为object或者array
        result = isArray(value) ? [] : {};
        for (const key in value) {
            if (hasOwnProperty.call(value, key)) {
                result[key] = isObject(value[key]) ? cloneDeep(value[key]) : value[key];
            }
        }
        return result;
    } else { // 其它数据类型
        return result;
    }
}

/** 对象相关方法 */
export class ObjectUtils {

    /** 获取变量类型 */
    static getTag(value: any): string {
        return getTag(value);
    }

    /** 检查value是否为object对象 */
    static isObj(value: any): boolean {
        return isObj(value);
    }

    /** 检查value是否为对象类型(Object、Array...) */
    static isObject(value: any): boolean {
        return isObject(value);
    }

    /** 对象深拷贝 */
    static cloneDeep(obj: any): any {
        return cloneDeep(obj);
    }

    /** 移除Object对象中属性值为空的键值对 */
    static deleteEmptyProperty(arg: any): any {
        return deleteEmptyProperty(arg);
    }
}
